package impl

import (
	"context"
	"fmt"

	"gitee.com/shiwjlinux/vblog01/apps/token"
	"gitee.com/shiwjlinux/vblog01/apps/user"
	"gitee.com/shiwjlinux/vblog01/conf"
	"gitee.com/shiwjlinux/vblog01/exception"
	"gitee.com/shiwjlinux/vblog01/ioc"
	"gorm.io/gorm"
)

var (
	_ token.Service = (*TokenServiceImpl)(nil)
	_ ioc.Object    = (*TokenServiceImpl)(nil)
)

type TokenServiceImpl struct {
	db   *gorm.DB
	user user.Service
}

func init() {
	ioc.Controller.Registry(token.AppName, &TokenServiceImpl{})
}

func (i *TokenServiceImpl) Init() error {
	i.db = conf.C().MySQL.GetDB()
	// i.user = impl.GetService()
	i.user = ioc.Controller.Get(user.AppName).(user.Service)
	return nil
}

// IssueToken 方法用于签发令牌
// IssueToken 方法用于生成一个新的Token
func (i *TokenServiceImpl) IssueToken(ctx context.Context,
	in *token.IssueTokenRequest,
) (*token.Token, error) {
	// 验证请求参数
	if err := in.Validate(); err != nil {
		return nil, err
	}

	// 创建查询用户请求
	queryUser := user.NewQueryUserRequest()
	queryUser.Username = in.Username

	// 查询用户
	set, err := i.user.QueryUser(ctx, queryUser)
	if err != nil {
		return nil, err
	}

	// 如果查询结果为空，则返回错误
	if len(set.Items) == 0 {
		return nil, token.ErrorTokenFailed
	}
	u := set.Items[0]
	// 验证用户密码
	if err := u.CheckPassword(in.Password); err != nil {
		return nil, token.ErrorTokenFailed
	}

	// 创建新的Token
	tk := token.NewToken(u)
	// 将Token保存到数据库
	if err := i.db.WithContext(ctx).Create(tk).Error; err != nil {
		return nil, exception.ErrServerInternal("保存失败")
	}
	return tk, nil
}

// RevolkToken 方法用于撤销令牌
func (i *TokenServiceImpl) RevolkToken(ctx context.Context,
	in *token.RevolkTokenRequest,
) (*token.Token, error) {
	if err := in.Validate(); err != nil {
		return nil, err
	}
	// 返回空值和错误
	tk := token.DefaultToken()

	err := i.db.
		WithContext(ctx).
		Where("access_token = ?", in.AccessToken).
		First(tk).
		Error
	if err == gorm.ErrRecordNotFound {
		return nil, exception.ErrorNotFound("令牌不存在")
	}

	if tk.RefreshToken != in.RefreshToken {
		return nil, fmt.Errorf("refresh token 不一致")
	}

	err = i.db.
		WithContext(ctx).
		Where("access_token = ?", in.AccessToken).
		Delete(tk).Error
	// if err == gorm.ErrRecordNotFound {
	// 	return nil, exception.ErrorNotFound("令牌不存在")
	// }
	if err != nil {
		return nil, exception.ErrServerInternal("撤销失败,%s", err)
	}
	return tk, nil
}

// ValidateToken函数用于验证Token
// ValidateToken 验证令牌
func (i *TokenServiceImpl) ValidateToken(ctx context.Context,
	in *token.ValidateTokenRequest,
) (*token.Token, error) {
	// 创建一个默认的Token对象
	tk := token.DefaultToken()
	// 在数据库中查找令牌
	err := i.db.WithContext(ctx).Where("access_token = ?", in.AccessToken).First(tk).Error
	// 如果令牌不存在，返回错误
	if err == gorm.ErrRecordNotFound {
		return nil, exception.ErrorNotFound("令牌不存在")
	}
	// 如果查询出错，返回错误
	if err != nil {
		return nil, exception.ErrServerInternal("令牌验证失败,%s", err)
	}

	// 判断刷新令牌是否过期
	if err := tk.RefreshTokenIsExpired(); err != nil {
		return nil, nil
	}
	// 判断访问令牌是否过期
	if err := tk.AccessTokenIsExpired(); err != nil {
		return nil, nil
	}

	// 根据用户名查询用户
	queryUser := user.QueryUserByUsername(tk.Username)

	// 查询用户
	set, err := i.user.QueryUser(ctx, queryUser)
	// 如果查询出错，返回错误
	if err != nil {
		return nil, err
	}
	// 如果用户不存在，返回错误
	if len(set.Items) == 0 {
		return nil, exception.ErrorNotFound("用户不存在")
	}

	// 设置用户的角色
	tk.Role = set.Items[0].Role
	// 返回令牌
	return tk, nil
}
